import matplotlib.pyplot as plt
import pydicom as dicom
import mycode.Tool as Tool
import numpy as np


class DataPreProcess:
    def __init__(self, path):
        self.INPUT_FOLDER = path
        # 建立一个列表，用于存储所有需要的dicom文件的地址
        self.lstFilesDCM = Tool.Load(path, '.dcm').load_scan()

    # 该函数表示一帧一帧单独读取DCM图像并展示
    def read_one_by_one(self):
        dcm_path = self.lstFilesDCM[0]
        # 用pydicom包解析对应路径的文件
        dcm = dicom.read_file(dcm_path)
        # 输出所具有的key列表
        print('该DCM文件所携带的key列表：', dcm.dir())
        # 输出文件所携带的一些信息
        print('患者姓名：', dcm.PatientName, '   患者ID：', dcm.PatientID)
        # 输出数据中PatientName这个key对应的tag编号、描述以及该文件中所对应的值
        print('PatientName这个Key的信息：', dcm.data_element('PatientName'))
        # 输出数据中PatientID这个key所对应的数据值类型，以及在该文件中所对应的值
        print('PatientID的数据类型', dcm.data_element('PatientID').VR, ' 该数据中PatientID的值', dcm.data_element('PatientID').value)
        # PixelData读取的是数据的原始二进制文件。
        pixelBytes = dcm.PixelData
        # 读取数据中的像素数组，然后用plt展示出来
        image = dcm.pixel_array
        # cmap是用于设置上色风格的，bone是一种黑蓝灰风格的
        # 具体配色色系可以参考 https://blog.csdn.net/weixin_39580795/article/details/102622004
        plt.imshow(image, cmap='bone')
        plt.show()

    # 该函数是将一系列单帧的DCM读入的操作
    def read_series(self):
        # 以第一张图片作为参考样本
        RefImage = dicom.read_file(self.lstFilesDCM[0])
        # 换个风格以区分两个函数
        plt.imshow(RefImage.pixel_array, cmap='viridis')
        plt.show()

        # 建立三维数组，分别记录长、宽、数据个数
        ConstPixelDims = (int(RefImage.Rows), int(RefImage.Columns), len(self.lstFilesDCM))
        # 输出数组的维度，
        print('数组维度为：', ConstPixelDims)
        # 设置三维图像的空间属性，PixelSpacing[0]和[1]代表的是像素点实际的长宽，单位为mm，SliceThickness表示的每个切片的厚度，单位也是mm
        ConstPixelSpacing = (0.0, 0.0, 0.0)
        try:
            if RefImage.PixelSpacing:
                ConstPixelSpacing = (float(RefImage.PixelSpacing[0]), float(RefImage.PixelSpacing[1]), float(RefImage.SliceThickness))
        except:
            pass
        # 三维数据为
        # xyz分别计算了长宽高，用行数、列数和张数分别与像素长宽以及切片高度相乘，得到一个三维立方体的大小
        x = y = z = (0.0, 0.0, 0.0)
        if ConstPixelSpacing[0] == ConstPixelSpacing[1] == ConstPixelSpacing[2] == 0:
            pass
        else:
            x = np.arange(0.0, (ConstPixelDims[0] + 1) * ConstPixelSpacing[0], ConstPixelSpacing[0])
            y = np.arange(0.0, (ConstPixelDims[1] + 1) * ConstPixelSpacing[1], ConstPixelSpacing[1])
            z = np.arange(0.0, (ConstPixelDims[2] + 1) * ConstPixelSpacing[2], ConstPixelSpacing[2])

        # 初始化一个跟一整个Series一样大的三位数组，类型也与Dicom格式一致，所有值初始化为0
        ArrayDicom = np.zeros(ConstPixelDims, dtype=RefImage.pixel_array.dtype)

        # 遍历所有的Dicom文件，读取图像数据并存放在numpy数组中
        for filenameDCM in self.lstFilesDCM:
            dcm = dicom.read_file(filenameDCM)
            ArrayDicom[:, :, self.lstFilesDCM.index(filenameDCM)] = dcm.pixel_array

        # 不同截面显示分别在imshow中设置显示哪个维度，[t,:,:]为矢状面，[:,t,:]为冠状面，[:,:,t]为轴状面
        # dpi越大，打印的图片越清晰
        plt.figure(dpi=1000)
        # 设置坐标轴都等长
        plt.axes().set_aspect('equal')
        plt.set_cmap(plt.gray())
        # 轴状面第150层展示
        plt.imshow(ArrayDicom[:, :, int(len(self.lstFilesDCM)/2)])
        plt.show()
        # 冠状面第255层展示
        plt.imshow(ArrayDicom[:, int(int(RefImage.Columns)/2), :])
        plt.show()
        # 矢状面第255层展示
        plt.imshow(ArrayDicom[int(int(RefImage.Rows)/2), :, :])
        plt.show()

    def run(self):
        # 这里读取的是一个series的所有DCM数据的路径
        self.read_one_by_one()
        self.read_series()